package jp.sourceforge.akjrcp.dropsomething2;

import java.io.IOException;

import jp.sourceforge.akjrcp.util.ProcessPrinter;
import jp.sourceforge.akjrcp.util.StatusBarUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;

public abstract class DropsomethingTab2 extends Composite implements IDropSomething2{
	public static Log log = LogFactory.getLog(DropsomethingTab2.class);
	
	
	
	private boolean canConvert;

	
	private String preferenceKey;//this tab name
	

	protected long progressMaxTime;
	
	protected long startTime;
	protected long progressTime;
	
	private ProcessPrinter processPrinter;
	
	private String cantConvertMessage;
	
	
	protected ListControler listControler;
	protected SettingControler settingControler;
	
	
	
	
	public String getPreferenceKey() {
		return preferenceKey;
	}
	private ViewPart viewPart;
	
	public void setPreferenceKey(String preferenceKey) {
		this.preferenceKey = preferenceKey;
	}
	public DropsomethingTab2(Composite parent, int style) {
		this(parent,style,null);
	}
	
	public DropsomethingTab2(Composite parent, int style,String preferenceKey) {
		super(parent, style);
		setPreferenceKey(preferenceKey);
		
		initialize(this);
		
		listControler=createListControler(this);
		settingControler=createSettingControler(this);
		
		if(settingControler!=null){
		new DropMonitor((Composite)settingControler.getControler());
		}
		
		if(listControler!=null){
			new DropMonitor((Composite)listControler.getControler());
			}
	}
	
	protected abstract void initialize(DropsomethingTab2 parent);



	
	public void progressTime(long time){
		if(time==0||progressMaxTime==0){
			return;
		}
		int p=(int) (time*100/progressMaxTime);
		setProgress(p);
	}
	
	public void setProgress(int persent){
		PlatformUI.getWorkbench().getDisplay().syncExec(new SetProgress(persent));//sync is better work.
	}
	
	public class SetProgress implements Runnable{
		private int value;
		public SetProgress(int value){
			this.value=value;
		}
		public void run() {
			listControler.setProgress(value);
		}
		
	}
	
	Setting lastSetting;
	Setting currentSetting;
	protected boolean cancelled;
	public class GetNext implements Runnable{
		
		
		public void run() {
			cancelled=false;
			currentSetting=listControler.next();
		}
		
	}

	
	public abstract SettingControler createSettingControler(IDropSomething2 parent);
	public abstract ListControler createListControler(IDropSomething2 parent);
	
	//for abstract class
	protected abstract void initializeExecutes();
	protected abstract void releaseExecutes();
	/*
	 * called from drag and drop
	 */
	public  void startWorking(){
		initializeExecutes();
		beforeExecutes();
		actionStartUI();
		
		Thread t = new Thread(new ConvertFile());
		t.start();
	}

	
	public class ConvertFile implements Runnable {
		public void run() {
			while (listControler.hasNext()) {
				lastSetting=currentSetting;
				PlatformUI.getWorkbench().getDisplay().syncExec( //changed to syncExec
						new GetNext());
				
				
				
				try {
					boolean result=inconvert(currentSetting);
					
					if(result){
						PlatformUI.getWorkbench().getDisplay().syncExec(new Successed(currentSetting));
					}else{
						PlatformUI.getWorkbench().getDisplay().syncExec(new Faild(currentSetting));
					}
					
				} catch (DropSomethingException e) {
					StatusBarUtils.showStatusBar(e.getStatusMessage());
					if(processPrinter!=null){
						try {
							processPrinter.printError(e.getLogMessage());
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					}
					cancellWorking();//TODO stop only each file
					e.printStackTrace();
				}
			}
			
			PlatformUI.getWorkbench().getDisplay().syncExec(new FinishConvert());
		}
		
	}

	

	
	public void cancellWorking(){
		cancelled=true;
		PlatformUI.getWorkbench().getDisplay().syncExec(new ActionCancel());
	}
	

	
	protected class ActionCancel extends Thread{
		public void run(){
			cancelExecute();
			actionCancelUI();
		}
	}
	
	/**
	 * abstract method main File execute
	 *
	 */
	public abstract boolean inconvert(Setting setting) throws DropSomethingException;	
	
	
	/**
	 * for executer
	 *
	 */
	public abstract void beforeExecutes();
	public abstract void afterExecutes();
	//cancell current
	public abstract void cancelExecute();

	/**
	 * for UI
	 */
	abstract protected void actionSuccessedUI(Setting setting);
	abstract protected void actionFaildUI(Setting setting);
	abstract protected void actionCancelUI();	//call list cancel
	abstract protected void actionStartUI();
	abstract protected void actionFinishUI();
	
	public class FinishConvert implements Runnable {
		public void run() {
			releaseExecutes();
			log.info("finish converting");
			afterExecutes();
			
			actionFinishUI();//for UI
		}
	}

	public class Successed implements Runnable {
		private Setting setting;
		public Successed(Setting setting){
			this.setting=setting;
		}
		public void run() {
			actionSuccessedUI(setting);
		}
	}
	
	public class Faild implements Runnable {
		private Setting setting;
		public Faild(Setting setting){
			this.setting=setting;
		}
		public void run() {
			actionFaildUI(setting);
		}
	}
	
	public class DropMonitor extends DropTargetAdapter {
		public DropMonitor(Composite controler){
			Transfer[] types = new Transfer[] { FileTransfer.getInstance() };

			int operations = DND.DROP_MOVE | DND.DROP_COPY;

			DropTarget target2 = new DropTarget(controler, operations);
			target2.setTransfer(types);

			target2.addDropListener(this);
		}
		public void dragEnter(DropTargetEvent event) {
			// log.infodrag enter:"+event.data);
		}

		public void dragOver(DropTargetEvent event) {
			// log.infodrag over:"+event.data);
		}

		public void drop(DropTargetEvent event) {
			//log.info("cancovert:"+isCanConvert());
			// log.info(event.data.getClass().getName());
			String files[] = (String[]) event.data;
			addDropFiles(files);
		}
	}
	
	
	public void addDropFiles(String files[]){
		if(isCanConvert()){
			

			

			Setting[] maps=settingControler.getSettings(files);
			for (int i = 0; i < maps.length; i++) {
				listControler.addSetting(maps[i]);
				}
			if(!listControler.isWorking() && listControler.isAutoStart()){
				startWorking();
				}else{
					actionStartUI();//chnage ui
				}
			}else{
				log.info("cant convert:"+cantConvertMessage);
				StatusBarUtils.showStatusBar(cantConvertMessage);
			}
	}

	public boolean isCanConvert() {
		return canConvert;
	}

	public void setCanConvert(boolean canConvert) {
		
		this.canConvert = canConvert;
	}
	

	
	public ViewPart getViewPart() {
		return viewPart;
	}
	public void setViewPart(ViewPart viewPart) {
		this.viewPart = viewPart;
	}
	

	public class DropSomethingException extends Exception{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private String logMessage;
		private String statusMessage;
		public DropSomethingException(String messages,String statusMessage,String logMessage){
			super(messages);
			this.statusMessage=statusMessage;
			this.logMessage=logMessage;
		}
		public String getLogMessage() {
			return logMessage;
		}
		public void setLogMessage(String logMessage) {
			this.logMessage = logMessage;
		}
		public String getStatusMessage() {
			return statusMessage;
		}
		public void setStatusMessage(String statusMessage) {
			this.statusMessage = statusMessage;
		}
	}


	public ProcessPrinter getProcessPrinter() {
		return processPrinter;
	}
	public void setProcessPrinter(ProcessPrinter processPrinter) {
		this.processPrinter = processPrinter;
	}
	public String getCantConvertStatusbarMessage() {
		return cantConvertMessage;
	}
	public void setCantConvertStatusbarMessage(String cantConvertMessage) {
		this.cantConvertMessage = cantConvertMessage;
	}
	public long getProgressMaxTime() {
		return progressMaxTime;
	}
	public void setProgressMaxTime(long progressMaxTime) {
		this.progressMaxTime = progressMaxTime;
	}

	public long getProgressTime() {
		return progressTime;
	}
	public void setProgressTime(long progressTime) {
		this.progressTime = progressTime;
	}
	public long getStartTime() {
		return startTime;
	}
	public void setStartTime(long startTime) {
		this.startTime = startTime;
	}


	
}
